Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Further enhance needless_borrow, mildly refactor redundant_clone #9386

Merged
merged 2 commits into from
Oct 8, 2022

Conversation

smoelius
Copy link
Contributor

This PR does the following:

  • Moves some code from redundant_clone into a new clippy_utils module called mir, and wraps that code in a function called dropped_without_further_use.
  • Relaxes the "is copyable" condition condition from Enhance needless_borrow to consider trait implementations #9136 by also suggesting to remove borrows from values dropped without further use. The changes involve the just mentioned function.
  • Separates redundant_clone into modules.

Strictly speaking, the last bullet is independent of the others. redundant_clone is somewhat hairy, IMO. Separating it into modules makes it slightly less so, by helping to delineate what depends upon what.

I've tried to break everything up into digestible commits.

r? @Jarcho

(@Jarcho I hope you don't mind.)

changelog: continuation of #9136

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Aug 27, 2022
@Jarcho
Copy link
Contributor

Jarcho commented Aug 27, 2022

Just did a quick check. Does the extension to needless_borrow handle closures? I think those have a separate MIR body from the containing function. I think what you have works fine, but it's better to check.

@smoelius
Copy link
Contributor Author

I just add a closure-related test. Please let me know if it doesn't address your specific concern.

@Jarcho
Copy link
Contributor

Jarcho commented Aug 27, 2022

The use of env in the test could have the borrow removed (not trivially, you would have to prove the closure is only called once). It would be better to have some use of it after the closure is created.

As this suggestion changes the drop order it would be better to limit this to types without a significant drop function. You can use has_significant_drop.

@smoelius
Copy link
Contributor Author

It would be better to have some use of it after the closure is created.

This has revealed a bug. Please give me a day or so to look into it.

smoelius added a commit to smoelius/rust-clippy that referenced this pull request Aug 30, 2022
@smoelius
Copy link
Contributor Author

smoelius commented Aug 30, 2022

@Jarcho
Copy link
Contributor

Jarcho commented Aug 30, 2022

You can try rebasing and see if that helps. Is it working locally?

@smoelius
Copy link
Contributor Author

smoelius commented Aug 30, 2022

I think I figured it out. Sorry for the noise.

Today's changes move the possible_borrower code under clippy_utils::mir so that it can be used in dereference.rs.

The bug I mentioned is resolved, and the PR should be ready for review (again).

@bors
Copy link
Contributor

bors commented Sep 3, 2022

☔ The latest upstream changes (presumably #9400) made this pull request unmergeable. Please resolve the merge conflicts.

@smoelius
Copy link
Contributor Author

smoelius commented Sep 3, 2022

Okay to rebase?

Copy link
Contributor

@Jarcho Jarcho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of things here:

  • This can calculate possible borrowers multiple times per function. It also fully recalculates the liveness bitset each time as well. What's the perf impact from this?
  • Some suggestions from this are arguably downgrades (see later comment for example).

Given the second point it might be better to only lint on temporaries.

clippy_dev/src/new_lint.rs Outdated Show resolved Hide resolved
@smoelius
Copy link
Contributor Author

smoelius commented Sep 4, 2022

A couple of things here:

  • This can calculate possible borrowers multiple times per function. It also fully recalculates the liveness bitset each time as well. What's the perf impact from this?
  • Some suggestions from this are arguably downgrades (see later comment for example).

Given the second point it might be better to only lint on temporaries.

This strategy feels a little extreme to me. For example, it would seem to eliminate a large number of valid suggestions from 29a7057.

To address the first bullet, we could compute the possible borrowers once (lazily) in a check_body implementation, and make the current check_expr a method of a visitor called from check_body (e.g., make the Option<PossibleBorrowMap<...>> a field of the visitor).

To address the second bullet, may I suggest the following alternative? For each body, build a map from def ids to substitutions used in calls to that def id. (This could also be done lazily.) Then, suggest to remove a & from an argument in a call to def_id only if it would not increase the total number of substitutions used in calls to def_id within the body.

Whichever way we go, can we make the current, unhindered strategy something that could be optionally enabled?

@Jarcho
Copy link
Contributor

Jarcho commented Sep 4, 2022

Most of the changes are on temporaries (52/74) by a quick count. Could limit locals to those which are used only once, which would lint almost all cases. The main point is to avoid changing something like:

let x = ...;
use_x(&x);
...
use_x_again(&x);

To address the first bullet, we could compute the possible borrowers once (lazily) in a check_body implementation, and make the current check_expr a method of a visitor called from check_body (e.g., make the Option<PossibleBorrowMap<...>> a field of the visitor).

That would unconditionally add another traversal over every function. which would probably be worse on average. Ideally we could store this in the lint pass, but that's not possible.

@smoelius
Copy link
Contributor Author

smoelius commented Sep 4, 2022

That would unconditionally add another traversal over every function.

I thought what I was proposing would conditionally add another traversal (i.e., if all of the conditions were met so that the possible borrowers were needed to proceed).

Why would it be unconditional?

Could limit locals to those which are used only once,

That sounds reasonable to me. Okay to turn this off with an option, though?

@Jarcho
Copy link
Contributor

Jarcho commented Sep 4, 2022

You suggested to switching the lint to use check_body with the current check_expr moved into a visitor, correct? That leaves the visitor with all the lints, plus the new visitor from check_body running over the code.

@smoelius
Copy link
Contributor Author

smoelius commented Sep 4, 2022

You suggested to switching the lint to use check_body with the current check_expr moved into a visitor, correct? That leaves the visitor with all the lints, plus the new visitor from check_body running over the code.

OK. I see what you are saying.

Then what if we essentially queued the arguments to needless_borrow_impl_arg_position inside Position::ImplArg, and actually processed those arguments/performed those calls in an implementation of check_body_post?

Admittedly, one thing I am not clear on is whether returning an Position::ImplArg as a possibility rather than a certainty would break the surrounding code. For example, would this code break if no warning were ultimately produced for the ImplArg? Maybe the answer is obvious to you.

} else if let Position::ImplArg(hir_id) = position {
(0, impl_msg, Some(hir_id))

@Jarcho
Copy link
Contributor

Jarcho commented Sep 5, 2022

I think you can make that work by storing the expression's HirId the target function's DefId and argument position and then running over all those in check_body_post. This would be slightly complicated by nested functions.

I'll check to see if we can change rustc to allow storing TyCtxt bounded items in lint passes as that would allow caching the MIR result directly.

Posted on zulip: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Allowing.20non.20.60'static.60.20lint.20passes/near/297154930

@smoelius
Copy link
Contributor Author

smoelius commented Sep 5, 2022

I'll check to see if we can change rustc to allow storing TyCtxt bounded items in lint passes as that would allow caching the MIR result directly.

Thanks!

Did you already start those changes? If not, I could make them. Please just let me know.

@Jarcho
Copy link
Contributor

Jarcho commented Sep 6, 2022

Implemented in rust-lang/rust#101501. Hopefully that will be synced to clippy this week.

@smoelius
Copy link
Contributor Author

smoelius commented Sep 6, 2022

Thanks, @Jarcho!

@smoelius
Copy link
Contributor Author

smoelius commented Sep 9, 2022

I saw you PR was merged. But it looks like it didn't make it in time for the most recent rustup?

If I'm reading everything right, the current toolchain (nightly-2022-09-08) is based on commit c2804e6, which is older than 8778809 (the one which includes your PR).

smoelius added a commit to smoelius/rust-clippy that referenced this pull request Sep 10, 2022
@Jarcho
Copy link
Contributor

Jarcho commented Sep 11, 2022

That is correct. Two weeks till the next sync.

smoelius added a commit to smoelius/rust-clippy that referenced this pull request Sep 17, 2022
@smoelius smoelius force-pushed the further-enhance-needless-borrow branch from 5860abf to dc4acf6 Compare September 30, 2022 01:50
smoelius added a commit to smoelius/rust-clippy that referenced this pull request Sep 30, 2022
smoelius added a commit to smoelius/rust-clippy that referenced this pull request Sep 30, 2022
@smoelius
Copy link
Contributor Author

I think this is ready for review again, @Jarcho.

(Rebasing was a bit of bear, so hopefully I did not screw it up.)

@bors
Copy link
Contributor

bors commented Sep 30, 2022

☔ The latest upstream changes (presumably #9510) made this pull request unmergeable. Please resolve the merge conflicts.

clippy_lints/src/dereference.rs Outdated Show resolved Hide resolved
clippy_lints/src/dereference.rs Outdated Show resolved Hide resolved
clippy_lints/src/utils/internal_lints.rs Outdated Show resolved Hide resolved
smoelius added a commit to smoelius/rust-clippy that referenced this pull request Oct 3, 2022
smoelius added a commit to smoelius/rust-clippy that referenced this pull request Oct 3, 2022
@smoelius smoelius force-pushed the further-enhance-needless-borrow branch 2 times, most recently from 5ad9b72 to 252f598 Compare October 3, 2022 21:25
@smoelius
Copy link
Contributor Author

smoelius commented Oct 3, 2022

I think the three most recent comments have been addressed.

@bors
Copy link
Contributor

bors commented Oct 4, 2022

☔ The latest upstream changes (presumably #9547) made this pull request unmergeable. Please resolve the merge conflicts.

@Jarcho
Copy link
Contributor

Jarcho commented Oct 5, 2022

I think the only thing remaining is the previous point about changing f1(&x); f2(&x); to f1(&x); f2(x);

@smoelius
Copy link
Contributor Author

smoelius commented Oct 5, 2022

I think the only thing remaining is the previous point about changing f1(&x); f2(&x); to f1(&x); f2(x);

Meaning don't suggest that, right?

It's possible there's a problem, but I think I addressed that, actually, e.g.:

@Jarcho
Copy link
Contributor

Jarcho commented Oct 5, 2022

So it is. I was going by the change in clippy_dev/src/new_lint.rs still being there. (there's no need to change this).

You can rebase and squash.

@smoelius
Copy link
Contributor Author

smoelius commented Oct 5, 2022

So it is. I was going by the change in clippy_dev/src/new_lint.rs still being there. (there's no need to change this).

It should have occurred to me to fix that.

I will fix that and any other similar changes before rebasing.

@smoelius smoelius force-pushed the further-enhance-needless-borrow branch from 252f598 to 9cc8da2 Compare October 7, 2022 11:32
@smoelius
Copy link
Contributor Author

smoelius commented Oct 7, 2022

The most recent push squashes all of the commits except for the "Fix adjacent code" ones.

The current "Fix adjacent code" commit is the result of rerunning the lint.

Sadly, the introduction of possible_borrowers eliminated more suggestions than I realized.

I think there may be ways possible_borrowers could be improved, but that could be the subject of a separate PR.

@Jarcho
Copy link
Contributor

Jarcho commented Oct 8, 2022

Everything looks good. If you can catch more single use cases that would be great.

Thank you. @bors r+

@bors
Copy link
Contributor

bors commented Oct 8, 2022

📌 Commit 9cc8da2 has been approved by Jarcho

It is now in the queue for this repository.

@bors
Copy link
Contributor

bors commented Oct 8, 2022

⌛ Testing commit 9cc8da2 with merge 272bbfb...

@bors
Copy link
Contributor

bors commented Oct 8, 2022

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: Jarcho
Pushing 272bbfb to master...

@bors bors merged commit 272bbfb into rust-lang:master Oct 8, 2022
@smoelius
Copy link
Contributor Author

smoelius commented Oct 8, 2022

Thank you. @bors r+

Thank you as well! Especially for rust-lang/rust#101501. 🙏

Cheers.

@smoelius smoelius deleted the further-enhance-needless-borrow branch October 8, 2022 22:34
bors added a commit that referenced this pull request Oct 20, 2022
Fix bug introduced by #9386

#9386 introduced a potential out-of-bounds array access. Specifically, a location returned by `local_assignments` could have  [`location.statement_index` equal to `mir.basic_blocks[location.block].statements.len()`](https://github.com/rust-lang/rust-clippy/blob/b8a9a507bf9e3149d287841454842116c72d66c4/clippy_utils/src/mir/mod.rs#L129), in which case the location would refer to the block terminator:
https://github.com/rust-lang/rust-clippy/blob/b8a9a507bf9e3149d287841454842116c72d66c4/clippy_lints/src/dereference.rs#L1204-L1206
I suspect the bug is not triggerable now, because of checks leading up to where it occurs. But a future code change could make it triggerable. Hence, it should be fixed.

r? `@Jarcho`

changelog: none
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants